<template>
	<div class="template-renderer">
		<!-- 模版类型选择器 -->
		<div class="template-selector" v-if="showSelector">
			<el-select v-model="selectedTemplateType" placeholder="请选择模版类型" @change="onTemplateTypeChange" class="template-type-select">
				<el-option v-for="opt in templateTypeOptions" :key="opt.value" :value="opt.value" :label="opt.label" />
			</el-select>
		</div>

		<!-- 字段配置面板 -->
		<div class="field-config-panel" v-if="showFieldConfig && fieldConfigs.length > 0">
			<div class="panel-header">
				<h4>字段配置</h4>
			</div>
			<div class="field-list">
				<div v-for="field in fieldConfigs" :key="field.key" class="field-item">
					<label>{{ field.label }}:</label>
					<el-input v-model="fieldValues[field.key]" :placeholder="field.placeholder" @input="updateTemplateContent" class="field-input"></el-input>
				</div>
			</div>
		</div>

		<!-- 模版内容展示区域 -->
		<div class="template-content" :class="{ 'preview-mode': previewMode }">
			<div class="template-html" v-html="renderedContent" :style="templateStyles"></div>
		</div>

		<!-- 操作按钮 -->
		<div class="template-actions" v-if="showActions">
			<el-button type="primary" @click="previewTemplate">预览</el-button>
			<el-button type="success" @click="exportTemplate">导出</el-button>
			<el-button @click="resetTemplate">重置</el-button>
		</div>
	</div>
</template>

<script setup lang="ts" name="TemplateRenderer">
/**
 * TemplateRenderer
 *
 * 用途：
 * - 渲染模板 HTML，支持字段占位符替换与印章位替换
 * - 可选内置 PDF 导出（html2pdf）
 * - 可选字段值转义（XSS 防护兜底），与 hooks/useTemplate 能力对齐
 *
 * 适配点：
 * - 模板类型来源于 templateConfigs，自动适配新增模板
 * - 外部可传入 sealData，用于替换 [SEAL_PLACEHOLDER]
 */
import { ref, computed, watch, nextTick } from 'vue';
import { ElMessage } from 'element-plus';
import html2pdf from 'html2pdf.js';
import { templateConfigs, TemplateField } from '../../hooks/useTemplate';

/**
 * 组件属性定义
 * - enablePdf：开启后点击“导出”即导出 PDF，否则通过事件上报 HTML
 * - escapeFieldValues：字段替换时进行 HTML 转义（建议开启）
 * - sealData：外部传入印章元数据（图片优先）
 */
interface Props {
	templateType?: string; // 模版类型
	templateContent?: string; // 模版内容
	fields?: Array<TemplateField>; // 字段配置
	showSelector?: boolean; // 是否显示模版类型选择器
	showFieldConfig?: boolean; // 是否显示字段配置面板
	showActions?: boolean; // 是否显示操作按钮
	previewMode?: boolean; // 是否为预览模式
	customStyles?: Record<string, any>; // 模版样式
	// 额外增强
	enablePdf?: boolean; // 是否启用内置PDF导出
	pdfFileName?: string; // 导出文件名
	escapeFieldValues?: boolean; // 替换时转义字段值，避免XSS
	sealData?: { id: string; name: string; image?: string } | null; // 外部传入印章数据用于替换
}

/**
 * 组件事件定义
 * - template-change：模板类型变更时触发（类型与当前内容）
 * - field-change：字段值变更时触发（当前字段集）
 * - preview/export：点击按钮时触发（传递渲染后的 HTML）
 */
interface Emits {
	(e: 'template-change', type: string, content: string): void;
	(e: 'field-change', values: Record<string, string>): void;
	(e: 'preview', content: string): void;
	(e: 'export', content: string): void;
}

// 定义组件属性
const props = withDefaults(defineProps<Props>(), {
	showSelector: true,
	showFieldConfig: true,
	showActions: true,
	previewMode: false,
	customStyles: () => ({}),
	enablePdf: false,
	pdfFileName: '模板.pdf',
	escapeFieldValues: true,
	sealData: null,
});

// 定义组件事件
const emit = defineEmits<Emits>();

// 响应式数据
const selectedTemplateType = ref('');
const currentTemplateContent = ref('');
const fieldValues = ref<Record<string, string>>({});

// 字段配置（来源于 templateConfigs，随选择的模板类型变化）
const fieldConfigs = computed(() => {
	if (selectedTemplateType.value && templateConfigs[selectedTemplateType.value]) {
		return templateConfigs[selectedTemplateType.value].fields;
	}
	return [];
});

// 模版类型下拉项（自动从配置生成，避免硬编码）
const templateTypeOptions = computed(() => Object.keys(templateConfigs).map((k) => ({ value: k, label: k })));

// 转义工具：避免字段值注入 v-html 导致的 XSS
const escapeHtml = (input: string) =>
	input.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;').replace(/'/g, '&#39;');

/**
 * 渲染后的内容
 * 顺序：字段替换 -> 印章占位符替换（无印章则移除）
 */
const renderedContent = computed(() => {
	let content = currentTemplateContent.value;

	// 替换字段占位符
	Object.keys(fieldValues.value).forEach((key) => {
		let value = fieldValues.value[key] || `[${key}]`;
		if (props.escapeFieldValues && value) {
			value = escapeHtml(value);
		}
		const regex = new RegExp(`\\[${key}\\]`, 'g');
		content = content.replace(regex, value);
	});

	// 替换印章占位符
	if (props.sealData) {
		const sealHtml = generateSealHtml(props.sealData);
		content = content.replace(/\[SEAL_PLACEHOLDER\]/g, sealHtml);
	} else {
		content = content.replace(/\[SEAL_PLACEHOLDER\]/g, '');
	}

	return content;
});

// ------- PDF 导出（样式模板与导出方法） -------
const pdfStyle = `
  <style>
    .pdf-export-html { max-width: 800px; margin: 0 auto; padding: 20px; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; line-height: 1.8; color: #333; }
    .pdf-export-html h1, .pdf-export-html h2, .pdf-export-html h3, .pdf-export-html h4, .pdf-export-html h5, .pdf-export-html h6 {
      margin-top: 1.2em; margin-bottom: 0.5em; font-weight: bold;
    }
    .pdf-export-html h1 { font-size: 22px; text-align: center; }
    .pdf-export-html h2 { font-size: 18px; }
    .pdf-export-html h3 { font-size: 16px; }
    .pdf-export-html p { margin: 8px 0; }
    .pdf-export-html table { border-collapse: collapse; width: 100%; margin: 12px 0; }
    .pdf-export-html th, .pdf-export-html td { border: 1px solid #ddd; padding: 8px; text-align: left; }
    .pdf-export-html img { max-width: 100%; height: auto; }
  </style>`;

/**
 * 生成并下载 PDF（基于 html2pdf）
 */
const downloadPdf = async () => {
	try {
		const element = document.createElement('div');
		element.innerHTML = pdfStyle + `<div class=\"pdf-export-html\">${renderedContent.value}</div>`;
		const opt = {
			margin: [10, 10, 10, 10],
			filename: props.pdfFileName,
			image: { type: 'jpeg', quality: 0.98 },
			html2canvas: {
				scale: window.devicePixelRatio > 2 ? 2 : window.devicePixelRatio || 1,
				useCORS: true,
				letterRendering: true,
			},
			jsPDF: { unit: 'mm', format: 'a4', orientation: 'portrait' },
		} as any;
		await (html2pdf() as any).set(opt).from(element).save();
		ElMessage.success('PDF导出成功');
	} catch (error) {
		// eslint-disable-next-line no-console
		console.error('PDF生成失败:', error);
		ElMessage.error('PDF导出失败，请稍后重试');
	}
};
/**
 * 生成印章 HTML：有图片优先显示图片，否则为文字印章（与 hooks/useTemplate 一致）
 */
const generateSealHtml = (seal: { id: string; name: string; image?: string }) => {
	if (seal.image) {
		return `<img src="${seal.image}" alt="印章" style="width: 100px; height: 100px; max-width: 100px; max-height: 100px; display: inline-block; vertical-align: middle; object-fit: contain; position: relative; z-index: 10; opacity: 0.8;" />`;
	}
	return `<div style="
        width: 100px; 
        height: 100px; 
        border: 2px solid #d32f2f; 
        border-radius: 50%; 
        display: inline-flex; 
        align-items: center; 
        justify-content: center; 
        text-align: center; 
        font-size: 10px; 
        font-weight: bold; 
        color: #d32f2f; 
        line-height: 1.2;
        background: rgba(211, 47, 47, 0.05);
        vertical-align: middle;
        box-sizing: border-box;
        position: relative;
        z-index: 10;
        opacity: 0.8;
      ">${seal.name}</div>`;
};

/**
 * 字段校验：仅校验必填字段非空
 */
const validateFields = () => {
	const errors: string[] = [];
	fieldConfigs.value.forEach((field) => {
		if (field.required && (!fieldValues.value[field.key] || fieldValues.value[field.key].trim() === '')) {
			errors.push(`${field.label}为必填项`);
		}
	});
	return errors;
};

// 模版样式（可通过 customStyles 扩展或覆盖）
const templateStyles = computed(() => ({
	fontFamily: 'SimSun, serif',
	fontSize: '16px',
	lineHeight: '2',
	color: 'var(--el-text-color-primary, #333)',
	...props.customStyles,
}));

/**
 * 模版类型变化处理：
 * - 注入默认 content
 * - 初始化字段默认值
 */
const onTemplateTypeChange = (type: string) => {
	selectedTemplateType.value = type;
	const config = templateConfigs[type];
	if (config) {
		currentTemplateContent.value = config.content;
		// 初始化字段值
		fieldValues.value = {};
		config.fields.forEach((field) => {
			fieldValues.value[field.key] = field.defaultValue || '';
		});
	} else {
		currentTemplateContent.value = '';
		fieldValues.value = {};
	}

	emit('template-change', type, currentTemplateContent.value);
};

// 更新模版内容（上报字段值变更）
const updateTemplateContent = () => {
	emit('field-change', fieldValues.value);
};

// 预览模版（先校验，后上报预览 HTML）
const previewTemplate = () => {
	const errors = validateFields();
	if (errors.length > 0) {
		ElMessage.error(errors.join('\n'));
		return;
	}
	emit('preview', renderedContent.value);
};

// 导出模版（可选 PDF 导出，否则上报 HTML）
const exportTemplate = () => {
	const errors = validateFields();
	if (errors.length > 0) {
		ElMessage.error(errors.join('\n'));
		return;
	}
	if (props.enablePdf) {
		downloadPdf();
		return;
	}
	emit('export', renderedContent.value);
};

// 重置模版（字段恢复默认值）
const resetTemplate = () => {
	fieldValues.value = {};
	fieldConfigs.value.forEach((field) => {
		fieldValues.value[field.key] = field.defaultValue || '';
	});
	updateTemplateContent();
};

// 监听 props 变化：外部传入类型/内容/字段时同步本地状态
watch(
	() => props.templateType,
	(newType) => {
		if (newType && newType !== selectedTemplateType.value) {
			onTemplateTypeChange(newType);
		}
	}
);

watch(
	() => props.templateContent,
	(newContent) => {
		if (newContent && newContent !== currentTemplateContent.value) {
			currentTemplateContent.value = newContent;
		}
	}
);

watch(
	() => props.fields,
	(newFields) => {
		if (newFields && newFields.length > 0) {
			newFields.forEach((field) => {
				if (field.defaultValue) {
					fieldValues.value[field.key] = field.defaultValue;
				}
			});
		}
	},
	{ immediate: true }
);

// 初始化：如外部指定了初始类型，加载其配置
const init = () => {
	if (props.templateType) {
		onTemplateTypeChange(props.templateType);
	}
};

/**
 * 暴露方法给父组件：
 * - updateTemplateContent/previewTemplate/exportTemplate/downloadPdf/resetTemplate
 * - getFieldValues/getRenderedContent
 */
defineExpose({
	updateTemplateContent,
	previewTemplate,
	exportTemplate,
	downloadPdf,
	resetTemplate,
	getFieldValues: () => fieldValues.value,
	getRenderedContent: () => renderedContent.value,
});

// 组件挂载时初始化
nextTick(() => {
	init();
});
</script>

<style scoped>
.template-renderer {
	display: flex;
	flex-direction: column;
	gap: 20px;
}

.template-selector {
	margin-bottom: 20px;
}

.template-type-select {
	width: 100%;
	max-width: 300px;
}

.field-config-panel {
	border: 1px solid var(--el-border-color, #e4e7ed);
	border-radius: 6px;
	padding: 20px;
	background: var(--el-fill-color-light, #fafafa);
}

.panel-header {
	margin-bottom: 15px;
}

.panel-header h4 {
	margin: 0;
	color: var(--el-text-color-primary, #333);
	font-size: 16px;
	font-weight: 600;
}

.field-list {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
	gap: 15px;
}

.field-item {
	display: flex;
	flex-direction: column;
	gap: 5px;
}

.field-item label {
	font-size: 14px;
	color: var(--el-text-color-regular, #606266);
	font-weight: 500;
}

.field-input {
	width: 100%;
}

.template-content {
	border: 1px solid var(--el-border-color, #e4e7ed);
	border-radius: 6px;
	padding: 30px;
	background: var(--el-bg-color, #fff);
	min-height: 400px;
}

.template-content.preview-mode {
	background: var(--el-bg-color, #fff);
	border: 2px solid var(--el-color-primary, #409eff);
}

.template-html {
	font-family: 'SimSun', serif;
	font-size: 16px;
	line-height: 2;
	color: var(--el-text-color-primary, #333);
}

.template-actions {
	display: flex;
	gap: 10px;
	justify-content: center;
	margin-top: 20px;
}

/* 模版内容样式 */
.template-html h1 {
	text-align: center;
	color: var(--el-text-color-primary, #333);
	font-size: 24px;
	font-weight: bold;
	margin: 30px 0;
}

.template-html p {
	margin: 8px 0;
	font-size: 16px;
	color: var(--el-text-color-primary, #333);
}

.template-html table {
	width: 100%;
	margin-top: 50px;
	border-collapse: collapse;
}

.template-html table td {
	padding: 8px 12px;
	vertical-align: bottom;
}

.template-html u {
	text-decoration: underline;
	text-decoration-color: var(--el-text-color-primary, #333);
	text-decoration-thickness: 1px;
}

.template-html strong {
	font-weight: bold;
	color: var(--el-text-color-primary, #333);
}

/* 响应式设计 */
@media (max-width: 768px) {
	.field-list {
		grid-template-columns: 1fr;
	}

	.template-content {
		padding: 20px;
	}

	.template-actions {
		flex-direction: column;
	}
}
</style>
